package com.cfpamf.athean.rabbit.mq.plus.domain.builder;

import java.util.Date;

import com.cfpamf.athean.rabbit.mq.plus.common.constant.BusinessConstants;
import com.cfpamf.athean.rabbit.mq.plus.domain.RabbitMqRetryInfo;
import com.cfpamf.athean.rabbit.mq.plus.validation.RabbitMqRetryValidation;
import com.cfpamf.athena.utils.DateUtils;
import com.cfpamf.athena.utils.JSONUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 类RabbitMqPlusRetryInfoBuilder.java的实现描述：
 *
 * @author Andy（陈洪桥）2022年11月25 17:20
 */
@Slf4j
public class RabbitMqPlusRetryInfoBuilder {

    /**
     * 构建首次重试消息对象
     * 
     * @param retryDurationByMinute
     *            重试时长（单位分钟）
     * @param isFailRightAwayRetry
     * @param messageId
     * @param data
     * @return
     */
    public static RabbitMqRetryInfo buildFirstRetryMessageBody(final int retryDurationByMinute,
        final boolean isFailRightAwayRetry, final String messageId, final String data) {
        Date messageTime = DateUtils.nowTime();
        // 立刻补偿后失败后的，首次重试时间规则固定5分钟后重试
        Date nextRetryTime = DateUtils.addMinute(messageTime, BusinessConstants.FIVE);
        if (Boolean.TRUE.equals(isFailRightAwayRetry)) {
            nextRetryTime = messageTime;// 立刻补偿
        }
        return newRabbitMqRetryInfoBuilder(messageId, retryDurationByMinute, BusinessConstants.ONE, messageTime,
            nextRetryTime, messageTime, retryDurationByMinute < BusinessConstants.FIVE, data);
    }

    /**
     * 构建首次之外的重试消息对象
     * 
     * @param retryDurationByMinute
     *            重试时长（单位分钟）
     * @param isFailRightAwayRetry
     * @param messageId
     * @param data
     * @return
     */
    public static RabbitMqRetryInfo buildRetryMessageBody(final int retryDurationByMinute,
        final boolean isFailRightAwayRetry, final String messageId, final String data) {
        Date messageTime = DateUtils.nowTime();
        RabbitMqRetryInfo message = mqMessageParse(data);
        // 重试时间计算规则【立即重试失败、5分钟后续重试时间为上次重试时间差*2，类推规则内上限小时内持续，延迟重试。】 根据上次延迟时间的分钟差计算重试时间
        // 如果开启了立刻补偿，补偿后失败后的，首次重试时间规则固定5分钟后重试
        int delayRetryMillisecond = message.getDelayRetryMillisecond();
        if (Boolean.TRUE.equals(isFailRightAwayRetry)
            && DateUtils.equals(message.getMessageTime(), message.getNextRetryTime())) {
            delayRetryMillisecond = BusinessConstants.FIVE;
        }
        // 本轮的延迟执行时间，下次消息延迟时间=计算上次消息延迟毫秒数 * 2
        Date nextRetryTime = DateUtils.addMillisecond(messageTime, (delayRetryMillisecond * BusinessConstants.TWO));
        boolean lastDelayRetryStatus = false;
        // 当前重试时间，大于或等于最后执行时间，表示当前为最后一次执行
        if (-1 != DateUtils.compareTo(nextRetryTime, message.getLastMessageTime())) {
            // 设置最后一次执行
            lastDelayRetryStatus = true;
            // 最后一次执行，重置延迟执行时间为最后执行时间
            nextRetryTime = message.getLastMessageTime();
        }
        return newRabbitMqRetryInfoBuilder(messageId, retryDurationByMinute,
            (message.getRetryNumber() + BusinessConstants.ONE), messageTime, nextRetryTime, messageTime,
            lastDelayRetryStatus, data);
    }

    /**
     * RabbitMq报文解析
     * 
     * @param data
     * @return
     */
    public static RabbitMqRetryInfo mqMessageParse(final String data) {
        return JSONUtils.jsonToBean(data, RabbitMqRetryInfo.class);
    }

    /**
     * RabbitMqRetryInfo 构建
     * 
     * @param messageId
     * @param retryDurationByMinute
     * @param currentRetryNumber
     * @param delayRetryTime
     * @param firstMessageTime
     * @param lastDelayRetryStatus
     * @param body
     * @return
     */
    private static RabbitMqRetryInfo newRabbitMqRetryInfoBuilder(String messageId, int retryDurationByMinute,
        int currentRetryNumber, Date messageTime, Date nextRetryTime, Date firstMessageTime,
        boolean lastDelayRetryStatus, String body) {
        if (log.isDebugEnabled()) {
            log.debug("【rabbitMq】构建消息对象=》messageId:{} retryDurationByMinute:{} currentRetryNumber:{} body:{}",
                messageId, retryDurationByMinute, currentRetryNumber, body);
        }
        /**
         * RabbitMqRetryInfo构建校验
         */
        RabbitMqRetryValidation.newRabbitMqRetryInfoBuilderValidation(messageId, retryDurationByMinute,
            currentRetryNumber, messageTime, nextRetryTime, firstMessageTime, lastDelayRetryStatus, body);

        return RabbitMqRetryInfo.builder().messageId(messageId)
            /**
             * 首次消息时间
             */
            .firstMessageTime(firstMessageTime)
            /**
             * 最后消息时间
             */
            .lastMessageTime(DateUtils.addMinute(firstMessageTime, retryDurationByMinute))
            /**
             * 消息时间
             */
            .messageTime(messageTime)
            /**
             * 重试次数
             */
            .retryNumber(currentRetryNumber)
            /**
             * 重试时长（单位分钟）
             */
            .retryDurationByMinute(retryDurationByMinute)
            /**
             * 下次执行时间（延迟到的时间）
             */
            .nextRetryTime(nextRetryTime)
            /**
             * 延迟执行毫秒
             */
            .delayRetryMillisecond(DateUtils.deltaT(messageTime, nextRetryTime).intValue())
            /**
             * 最后一次重试
             */
            .lastDelayRetryStatus(lastDelayRetryStatus)
            /**
             * 消息内容体
             */
            .body(body).build();
    }

}
